﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PortScanner
{
    public partial class Form1 : Form
    {
        //锁
        object obj = new object();
        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            Type dgvType = this.dataGridView1.GetType();
            PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
            pi.SetValue(this.dataGridView1, true, null);
            initData();
        }

        private void initData()
        {
            Config config = Config.LoadConfig();
            textBox1.Text = config.Host;
            textBox2.Text=config.Timeout.ToString();
            textBox3.Text = config.Ports;
            numericUpDown1.Value = config.ThreadCount ;
        }
        private void saveData()
        {
            Config config = Config.LoadConfig();
            config.Host=textBox1.Text;
            config.Timeout = int.Parse(textBox2.Text);
            config.Ports = textBox3.Text;
            config.ThreadCount = (int)numericUpDown1.Value;
            config.SaveConfig();
        }

        Thread taskThread;
        Thread timerThread;

        private void button1_Click(object sender, EventArgs e)
        {
            int threadCount = (int)numericUpDown1.Value;
            if (threadCount > 100)
            {
                DialogResult result = MessageBox.Show("确定要启动" + threadCount + "个线程来进行扫描吗，不知道你的CPU扛得住不！！", "提示", MessageBoxButtons.YesNo);

                if (result == DialogResult.No)
                {
                    return;
                }
            }
            saveData();
            try
            {
                List<int> ports = getPorts();
                string host = GetIPv4Address(textBox1.Text.Trim());
                if (host == null)
                {
                    MessageBox.Show("无法解析的主机"+ textBox1.Text.Trim());
                    return;
                }
                int timeout = getTimeout();
                taskThread = new Thread(() => startScanner(ports, host, timeout));
                taskThread.Start();

                timerThread = new Thread(() =>
                {
                    try
                    {
                        startTimer();
                    }
                    catch (Exception ex) { }
                });
                timerThread.Start();
                button1.Enabled = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private string GetIPv4Address(string host)
        {
            if (IPAddress.TryParse(host, out IPAddress ipAddress) && ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                // 输入的主机是有效的IPv4地址
                return host;
            }
            else
            {
                // 尝试进行域名解析
                try
                {
                    IPAddress[] ipAddresses = Dns.GetHostAddresses(host);

                    foreach (IPAddress addr in ipAddresses)
                    {
                        if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                        {
                            // 返回找到的第一个IPv4地址
                            return addr.ToString();
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception($"Error resolving host {host}: {ex.Message}");
                }
                return null;
            }
        }

        private void startTimer()
        {
            // 创建 Stopwatch 实例
            Stopwatch stopwatch = new Stopwatch();
            // 启动计时
            stopwatch.Start();
            while (true)
            {
                // 获取经过的时间
                TimeSpan elapsedTime = stopwatch.Elapsed;

                // 输出时:分:秒:毫秒形式
                string formattedTime = $"{elapsedTime.Hours:D2}:{elapsedTime.Minutes:D2}:{elapsedTime.Seconds:D2}:{elapsedTime.Milliseconds:D3}";
                label5.Text = formattedTime;
                bool v = setLabel();
                if (v)
                {
                    break;
                }
            }
            timerThread = null;
            button1.Enabled = true;
            taskThread = null;
        }

        private bool setLabel()
        {
            int handleCount = successCount + failureCount;
            label8.Text = handleCount.ToString();
            label10.Text = (totalCount - handleCount).ToString();
            label12.Text = successCount.ToString();
            label14.Text = failureCount.ToString();
            return handleCount == totalCount;
        }

        static int successCount = 0;
        static int failureCount = 0;
        static int totalCount = 0;
        static int timeout = 0;
        Semaphore semaphore;
        private async void startScanner(List<int> ports, string host, int t)
        {
            dataGridView1.Rows.Clear();
            int threadCount = (int)numericUpDown1.Value;
            semaphore = new Semaphore(threadCount, threadCount);
            timeout = t;
            totalCount = ports.Count;
            label7.Text = totalCount.ToString();
            successCount = 0;
            failureCount = 0;
            foreach (int port in ports)
            {
                ScannerInfo scannerInfo = new ScannerInfo(host, port, "连接中");
                Task.Run(async () =>
                {
                    semaphore.WaitOne(); // 请求信号量，如果已满则阻塞线程
                    try
                    {
                        await runTask(scannerInfo);
                    }
                    finally
                    { semaphore.Release(); }
                });
            }
        }


        private async Task runTask(ScannerInfo scannerInfo)
        {
            bool res = await testTpcConnect(scannerInfo);
            if (res)
            {
                DataGridViewRow dataGridViewRow = addRow(scannerInfo);
                dataGridViewRow.Cells[2].Value = "开放";
                dataGridViewRow.DefaultCellStyle.BackColor = Color.LightGreen;
                Interlocked.Increment(ref successCount);
            }
            else
            {
                Interlocked.Increment(ref failureCount);
            }
        }
        private DataGridViewRow addRow(ScannerInfo scannerInfo)
        {
            lock (obj)
            {
                int v = dataGridView1.Rows.Add(scannerInfo.host, scannerInfo.port, scannerInfo.status);
                DataGridViewRow dataGridViewRow = dataGridView1.Rows[v];
                return dataGridViewRow;
            }
        }

        private async Task<bool> testTpcConnect(ScannerInfo scannerInfo)
        {
            string target = scannerInfo.host;
            int port = scannerInfo.port;
            try
            {
                using (var tcpClient = new TcpClient())
                {
                    var connectTask = tcpClient.ConnectAsync(target, port);
                    var timeoutTask = Task.Delay(timeout);

                    // 等待连接或超时
                    await Task.WhenAny(connectTask, timeoutTask);

                    if (connectTask.IsCompleted && !connectTask.IsFaulted && !connectTask.IsCanceled)
                    {
                        // 连接成功
                        return true;
                    }
                    else
                    {
                        // 连接超时
                        return false;
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        private int getTimeout()
        {
            return int.Parse(textBox2.Text.Trim());
        }

        private List<int> getPorts()
        {
            List<int> ports = new List<int>();
            string[] rows = textBox3.Text.Split('\n');
            foreach (string row in rows)
            {
                if (row.Contains("-"))
                {
                    string[] split = row.Split('-');
                    int a = int.Parse(split[0]);
                    int b = int.Parse(split[1]);
                    if (a > b)
                    {
                        throw new Exception(a + ">" + b);
                    }
                    for (int i = a; i <= b; i++)
                    {
                        ports.Add(i);
                    }
                }
                else
                {
                    int port = int.Parse(row);
                    ports.Add(port);
                }
            }
            ports.Sort();
            return ports;
        }
    }
}
